/*
error_state.c
offer service layer error state  and error message post to IOT cloud
designed by lunantng

----------------------
2020-11-20 10:50:51
create file
----------------------
*/

#include "error_state.h"
#include "string.h"
#include "stdlib.h"
#include "../../include/aos/kernel.h"
#include "../bsp/cli_cmd.h"
#include "stdio.h"
#include "mqtt.h"

static int xp_error_post(ERROR_terminal tml);
static void xp_error_check_thread(void *arg);
static char *xp_errorState_washerJson(void);
static char *xp_errorState_dryerJson(void);
static char *xp_station_status_string_get(void);
static void (*xp_error_state_check)(void);


static ERROR_class error={0};
static char json[1024],agvJson[100],post_buf[1024];


/*
    清除终端所有错误
*/
void xp_robot_error_clear(ERROR_terminal tml){
    switch(tml){
    case station:
        memset(&error.station,0,sizeof(ERROR_station));
        break;
    case washer:
        memset(&error.washer,0,sizeof(ERROR_washer));
        break;
    case dryer:
        memset(&error.dryer,0,sizeof(ERROR_dryer));
        break;
    default:
        println("no this terminal");
        break;
    }
}

/*
error mudule init
param:
    mq:mqtt obj
    type: terminal type,station /washer /dryer
return:
    0=success
*/
int xp_error_init(MQTT_class *mq,ERROR_terminal tml){
    memset(&error,0,sizeof(ERROR_class));
    if(mq==NULL){
        perr("mqtt == NULL~");
        return -1;
    }
    error.tml=tml;
    error.mqtt=mq;
    error.init=1;
    xp_error_state_check=NULL;
    if(aos_task_new("error module",xp_error_check_thread,NULL,2048)!=0){
        return -1;
    }
    println("error module init success~");
    return 0;
}


/*
updata error status
param:
    err:err obj
*/
void xp_error_update(ERROR_class *err){
    memcpy(&error,err,sizeof(ERROR_class));
}


/*
get error status obj
return: the error status pointer
*/
ERROR_class *xp_error_statusObj_get(void){
    return &error;
}


/*
upload error status 
return:
    0=success
*/
int xp_error_upload(void){
    static ERROR_class record={0};
    static int post_try=0;
    int rec=0;

    if(error.init==0){
        perr("error module no init~");
        return -1;
    }
    if(error.tml==station){
        rec=memcmp(&record.station,&error.station,sizeof(ERROR_station));
    }
    if(rec!=0||post_try!=0){
        if(rec!=0){
            println("error status have a change, will uploard~");
        }
        else if(post_try!=0){
            println("station error post retry!");
        }
        //post message
        memcpy(&record,&error,sizeof(ERROR_class));
        if(xp_error_post(error.tml)==0){
            post_try=0;
        }
        else{
            post_try=1;
            return -1;
        }
    }
    return 0;
}


/*
post error json string
return:
    0=success
*/
static int xp_error_post(ERROR_terminal tml){
    char *j;
    int try=0;
    println("post error state~");
    if(tml==station){
        j=xp_errorState_stationJson();
    }
    // else if(tml==washer){
    //     j=xp_errorState_washerJson();
    // }
    // else if(tml==dryer){
    //     j=xp_errorState_dryerJson();
    // }
    else{
        return 0;
    }
    sprintf(post_buf,"{\"error\":\"%s\"}",j);
    println("error json:%s",post_buf);
    if(xp_mqtt_post_property(error.mqtt,post_buf)<0){
        println("xp error post message fail ,next retry !");
        return -1;
    }
    // while(xp_mqtt_post_property(error.mqtt,post_buf)<0){
    //     aos_msleep(10000);
    //     println("xp_error_post message retry !");
    //     try++;
    //     if(try>3){
    //         perr("post error fail,try %d times.",try);
    //         return -1;
    //     }
    // }
    return 0;
}


/*
regist error check function
param:
    check_fun: check function
*/
void xp_error_state_check_regist(void (*check_fun)(void)){
    xp_error_state_check=check_fun;
}


/*
upload station status massage
param:
    cycle_time: post cycle time  seconds
return:
    0= nothing
    1= post success
   -1= post fail
*/
static int xp_station_status_upload(int cycle_time){
    static u64 time_last=0;
    u64 time_now=aos_now_ms();
    
    if((time_now-time_last)/1000>cycle_time){
        time_last=time_now;
        sprintf(post_buf,"{\"status\":\"%s\"}",xp_station_status_string_get());
        // println("%s",post_buf);
        if(xp_mqtt_post_property(error.mqtt,post_buf)<0){
            perr("post status massage fail, try next !");
            return -1;
        }
        return 1;
    }
    return 0;
}


/*
upload terminal status massage
use for keep connect
param:
    cycle_time: post cycle time seconds
return:
    0= nothing
    1= post success
   -1= post fail
*/
static int xp_terminal_status_upload(int cycle_time){
    static u64 time_last=0;
    u64 time_now=aos_now_ms();

    if((time_now-time_last)/1000>cycle_time){
        time_last=time_now;
        sprintf(post_buf,"{\"status\":\"keep live\"}");
        if(xp_mqtt_post_property(error.mqtt,post_buf)<0){
            perr("post status massage fail, try next !");
            return -1;
        }
        return 1;
    }
    return 0;
}

/*
error status check thread
*/
static void xp_error_check_thread(void *arg){

    if(error.init!=1){
        perr("error module no init~ exit thread~");
        aos_task_exit(0);
    }
    aos_msleep(10000);
    while(1){
        if(xp_error_state_check!=NULL){
            xp_error_state_check();
        }
        xp_error_upload();
        aos_msleep(500);
        if(error.tml==station){
            xp_station_status_upload(10);
        }
        else{
            xp_terminal_status_upload(10);
        }

        aos_msleep(1500);
    }
}


/*********************************make json***********************************/
/*
get station error element string from address
param:
    element address
return:
    ""=no matched element
*/
static char * xp_errorState_station_element(u8 *element){
    static char no[]="";
    
    if(element==&error.station.station_washer){
        get_param_string(error.station.station_washer);
    }
    else if(element==&error.station.station_dryer){
        get_param_string(error.station.station_dryer);
    }
    else if(element==&error.station.station_emergency){
        get_param_string(error.station.station_emergency);
    }
    else if(element==&error.station.station_park){
        get_param_string(error.station.station_park);
    }
    else if(element==&error.station.washer_lifter){
        get_param_string(error.station.washer_lifter);
    }
    else if(element==&error.station.washer_turner){
        get_param_string(error.station.washer_turner);
    }
    else if(element==&error.station.washer_wheel){
        get_param_string(error.station.washer_wheel);
    }
    else if(element==&error.station.washer_collision){
        get_param_string(error.station.washer_collision);
    }
    else if(element==&error.station.washer_emergency){
        get_param_string(error.station.washer_emergency);
    }
    else if(element==&error.station.washer_press){
        get_param_string(error.station.washer_press);
    }
    else if(element==&error.station.washer_freq){
        get_param_string(error.station.washer_freq);
    }
    else if(element==&error.station.washer_encoder){
        get_param_string(error.station.washer_encoder);
    }
    else if(element==&error.station.washer_lidar){
        get_param_string(error.station.washer_lidar);
    }
    else if(element==&error.station.dryer_lifter){
        get_param_string(error.station.dryer_lifter);
    }
    else if(element==&error.station.dryer_wheel){
        get_param_string(error.station.dryer_wheel);
    }
    else if(element==&error.station.dryer_collision){
        get_param_string(error.station.dryer_collision);
    }
    else if(element==&error.station.dryer_freq){
        get_param_string(error.station.dryer_freq);
    }
    else if(element==&error.station.dryer_emergency){
        get_param_string(error.station.dryer_emergency);
    }
    else if(element==&error.station.dryer_encoder){
        get_param_string(error.station.dryer_encoder);
    }
    else if(element==&error.station.dryer_lidar){
        get_param_string(error.station.dryer_lidar);
    }
    return no;
}


/*
make station json
return: json string
*/
char *xp_errorState_stationJson(void){
    char buf[200]={0},c_buf[20];
    int foot=0;
    u8 *value=0,error_flag=0;
    u8 *addr=&error.station.station_washer;
    int encode=1;

    /*sprintf(json,"{%s:%s,","\"tml\"","\"station\"");
    sprintf(buf,"\"power\":%d,",error.station.power);
    strcat(json,buf);
    sprintf(buf,"\"washer1\":%d,",error.station.washer1);
    strcat(json,buf);
    sprintf(buf,"\"washer2\":%d,",error.station.washer2);
    strcat(json,buf);
    sprintf(buf,"\"dryer\":%d,",error.station.dryer);
    strcat(json,buf);
    sprintf(buf,"\"emergency\":%d,",error.station.emergency);
    strcat(json,buf);
    sprintf(buf,"\"offline1\":%d,",error.station.offline1);
    strcat(json,buf);
    sprintf(buf,"\"offline2\":%d",error.station.offline2);
    strcat(json,buf);

    strcat(json,"}");
    */
    // sprintf(buf,"{");
    for(int i=0;i<sizeof(ERROR_station);i++){
        value=(u8*)(addr+i);

        if(value==&error.station.station_washer){
            encode=1;
        }
        else if(value==&error.station.washer_lifter){
            encode=101;
        }
        else if(value==&error.station.dryer_lifter){
            encode=201;
        }

        if(*value){
            if(foot>0){
                strcat(buf,",");
            }
            sprintf(c_buf,"%d:%d",encode,*value);
            strcat(buf,c_buf);
            foot++;
            error_flag++;
            // perr("%s:%d.",xp_errorState_station_element(addr+i),value);
        }
        encode++;
        if(strlen(buf)>190){
            break;
        }
    }
    // strcat(buf,"}");
    if(error_flag==0){
        strcpy(json,"No error !");
    }
    else {
        strcpy(json,buf);
    }

    return json;
}


/*
make agv json
return:json string
*/
static char *xp_errorState_agvJson(void){
    char buf[100];
    ERROR_agv *agv;

    if(error.tml==station)return NULL;
    else if(error.tml==washer){
        agv=&error.washer.agv;
    }
    else if(error.tml==dryer){
        agv=&error.dryer.agv;
    }
    sprintf(agvJson,"\"agv\":{\"wheel0\":%d,",agv->wheel0);
    sprintf(buf,"\"wheel1\":%d,",agv->wheel1);
    strcat(agvJson,buf);
    sprintf(buf,"\"lidar0\":%d,",agv->lidar0);
    strcat(agvJson,buf);
    sprintf(buf,"\"lidar1\":%d,",agv->lidar1);
    strcat(agvJson,buf);
    sprintf(buf,"\"safty\":%d,",agv->safty);
    strcat(agvJson,buf);
    sprintf(buf,"\"tooNear\":%d",agv->tooNear);
    strcat(agvJson,buf);

    strcat(agvJson,"}");
    return agvJson;
}

/*
make washer json
return: json string
*/
static char *xp_errorState_washerJson(void){
    char buf[50];

    sprintf(json,"{\"tml\":\"%s\",","washer");
    sprintf(buf,"\"lifter\":%d,",error.washer.lifter);
    strcat(json,buf);
    sprintf(buf,"\"turner\":%d,",error.washer.turner);
    strcat(json,buf);
    sprintf(buf,"\"putter\":%d,",error.washer.putter);
    strcat(json,buf);
    sprintf(buf,"\"door\":%d,",error.washer.door);
    strcat(json,buf);
    sprintf(buf,"\"brush\":%d,",error.washer.brush);
    strcat(json,buf);
    sprintf(buf,"\"conllision\":%d,",error.washer.conllision);
    strcat(json,buf);
    sprintf(buf,"\"emergency\":%d,",error.washer.emergency);
    strcat(json,buf);
    sprintf(buf,"\"offline\":%d,",error.washer.offline);
    strcat(json,buf);


    strcat(json,xp_errorState_agvJson());
    strcat(json,"}");
    return json;
}


/*
make dryer json
return: json string
*/
static char *xp_errorState_dryerJson(void){
    char buf[50];

    sprintf(json,"{\"tml\":\"%s\",","dryer");
    sprintf(buf,"\"lifter\":%d,",error.dryer.lifter);
    strcat(json,buf);
    sprintf(buf,"\"swing\":%d,",error.dryer.swing);
    strcat(json,buf);
    sprintf(buf,"\"wind\":%d,",error.dryer.wind);
    strcat(json,buf);
    sprintf(buf,"\"door\":%d,",error.dryer.door);
    strcat(json,buf);
    sprintf(buf,"\"conllision\":%d,",error.dryer.conllision);
    strcat(json,buf);
    sprintf(buf,"\"emergency\":%d,",error.dryer.emergency);
    strcat(json,buf);
    sprintf(buf,"\"offline\":%d,",error.dryer.offline);
    strcat(json,buf);


    strcat(json,xp_errorState_agvJson());
    strcat(json,"}");
    return json;    
}

/*
get post station status massage string
*/
static char *xp_station_status_string_get(void){
    ERROR_station_status *status=&error.station_status;
    
    sprintf(json,"{%d;%d;%d;%.2f;\
                [%.2f,%.2f];[%.2f,%.2f];[%.2f,%.2f];%.2f;\
                [%d,%d,%.2f];[%d,%d,%.2f]}",
                status->error,status->wash_start_count,status->washing,status->water_m3,
                status->A_phase.voltage_v,status->A_phase.current_a,
                    status->B_phase.voltage_v,status->B_phase.current_a,
                    status->C_phase.voltage_v,status->C_phase.current_a,
                status->electricity_kwh,
                status->washer_location.x,status->washer_location.y,status->washer_location.angle/1000.0,
                    status->dryer_location.x,status->dryer_location.y,status->dryer_location.angle/1000.0\
            );
    return json;
}


/*************************************debug*******************************/
//error debug
int xp_error_debug(char *type,char *fun,char *param){
    if(strcmp(type,"error")!=0)return 0;
    else if(strcmp(fun,"post")==0){
        if(strcmp(param,"station")==0){
            xp_error_post(station);
        }
        else if(strcmp(param,"washer")==0){
            xp_error_post(washer);
        }
        else if(strcmp(param,"dryer")==0){
            xp_error_post(dryer);
        }
        else{
            println("no matched type !");
        }
    }
    else{
        return 0;
    }
    return 1;
}




//end of the file
